package ru.ifmo.network.skype.network;

import org.apache.log4j.Logger;
import ru.ifmo.network.skype.network.data.MessageType;
import ru.ifmo.network.skype.network.data.UserAddress;

import java.io.*;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * @author avhaliullin
 */
public class UDPMessageSender implements MessageHandler {
    private static final Logger log = Logger.getLogger(UDPMessageSender.class);

    private final int port;
    private final DatagramSocket socket;

    public UDPMessageSender(int port) throws SocketException {
        this.port = port;
        socket = new DatagramSocket();
    }

    @Override
    public void handleHello(UserAddress userAddress) {
        try {
            sendDatagram(new ObjectStreamSender() {
                public void send(ObjectOutput out) throws IOException {
                    out.writeObject(MessageType.GOODBYE.getValue());
                }
            });
        } catch (IOException e) {
            log.error(e);
        }
    }

    @Override
    public void handleGoodbye(UserAddress userAddress) {
        try {
            sendDatagram(new ObjectStreamSender() {
                public void send(ObjectOutput out) throws IOException {
                    out.writeObject(MessageType.HELLO.getValue());
                }
            });
        } catch (IOException e) {
            log.error(e);
        }
    }

    @Override
    public void handleAudio(UserAddress userAddress, final long serialId, final byte[] data) {
        try {
            sendDatagram(new ObjectStreamSender() {
                public void send(ObjectOutput out) throws IOException {
                    out.writeObject(MessageType.AUDIO_DATA.getValue());
                    out.writeObject(serialId);
                    out.writeObject(data);
                }
            });
        } catch (IOException e) {
            log.error(e);
        }
    }

    @Override
    public void handleGroup(UserAddress userAddress, final long groupId, final byte[] data) {
        try {
            sendDatagram(new ObjectStreamSender() {
                public void send(ObjectOutput out) throws IOException {
                    out.writeObject(MessageType.SECURE.getValue());
                    out.writeObject(groupId);
                    out.writeObject(data);
                }
            });
        } catch (IOException e) {
            log.error(e);
        }
    }

    private synchronized void sendDatagram(ObjectStreamSender sender) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream os = new ObjectOutputStream(new BufferedOutputStream(byteArrayOutputStream));
        sender.send(os);
        os.flush();
        byte[] buffer = byteArrayOutputStream.toByteArray();
        socket.send(new DatagramPacket(buffer, buffer.length, InetAddress.getByName("255.255.255.255"), port));
    }

    private interface ObjectStreamSender {
        public void send(ObjectOutput out) throws IOException;
    }

}
